package edu.gmu.project.swe;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * Client supports uploading and downloading files
 * 
 * @author quynhtran
 *
 */
public class Client {

	private String welcomeRequest = "Welcome to file sharing client!\n"
			+ "Please enter in the file server addresses (host:port, host:port):";
	private String menu = "\nMENU\n0. Exit\n1. Connect to server in this session\n2. View files on server\n"
			+ "3. Download file name\n4. Upload file (full file path)\nPlease select an option: ";
	private Scanner scan;

	private Socket s = null;
	private BufferedReader in;
	private PrintWriter out;
	private String[] response;
	private HashMap<String, String> fileMap = new HashMap<String, String>();
	private static FileOutputStream fos;
	private static BufferedOutputStream bos;
	private static BufferedInputStream bis;
	private static InputStream is;
	BufferedOutputStream bout;

	public Client() {
		scan = new Scanner(System.in);
	}

	public void run() throws IOException {

		int choice = -1;
		String serverList = null;
		String[] servers = null;
		// Keep asking until they enter the valid format
		while (serverList == null) {
			// Print out the welcome request
			System.out.print(welcomeRequest);
			// Scan for the server list
			serverList = scan.nextLine();
			serverList = serverList.replaceAll(" ", "");
			if (serverList.isEmpty() || !serverList.contains(":")) {
				System.out.println("Invalid entry\n");
				serverList = null;
			} else {
				// Split the servers by commas

				servers = serverList.split(",");
				System.out.println("Saved:");
				for (String s : servers) {
					System.out.println(s);
				}
			}
		}
		while (choice != 0) {
			if (serverList != null)
				System.out.print(menu);
			try {
				choice = scan.nextInt();
			} catch (InputMismatchException e) {
				System.out.println("\nInvalid response");
				// Throw away the broken scanner and get a new one
				scan = new Scanner(System.in);
				choice = -1;
			}
			if (choice == 1) {
				// Print out the registered server
				System.out.println("\n>> Registered servers are:");
				for (int i = 0; i < servers.length; i++) {
					System.out.println(i + " - " + servers[i]);
				}
				// Select the server to connect
				System.out.print("Please select one to connect:");
				int sel = scan.nextInt();
				if (sel < servers.length) {
					System.out.println("Connecting to " + servers[sel] + "...");
					String[] server = servers[sel].split(":");
					try {
						if (s == null) {
							s = new Socket(server[0],
									Integer.valueOf(server[1]));
							out = new PrintWriter(s.getOutputStream(), true);
							is = s.getInputStream();
							in = new BufferedReader(new InputStreamReader(
									s.getInputStream()));
							bout = new BufferedOutputStream(s.getOutputStream());
							bis = new BufferedInputStream(s.getInputStream());
						}
						System.out.println("Connected!");
					} catch (NumberFormatException e) {
						System.out.println("Invalid entry:" + e.getMessage());
					} catch (UnknownHostException e) {
						System.out.println("Invalid host name:"
								+ e.getMessage());
					} catch (IOException e) {
						System.out.println("Error:" + e.getMessage());
					}
				} else {
					System.out.print("Invalid choice.");
				}
			} else if (choice == 2) {
				if (s != null) {
					// Build the File request message to send to server
					String msg = String.valueOf(MsgCode.FILE_REQUEST.getValue()
							+ "-" + MsgCode.FILE_REQUEST.name());
					System.out.println(msg);

					// Send out the file request
					out.println(msg);
					String inputLine = "";
					while ((inputLine = in.readLine()) != null) {
						// System.out.println("HERE:" + inputLine);
						// Split file name and file size
						if (inputLine.contains("2")) {
							// split 2 - file.txt:393, file2.txt:32342
							response = inputLine.split("-");
							//
							String[] fList = response[1].split(",");
							for (String f : fList) {
								String[] fileNoffset = f.split(":");
								fileMap.put(fileNoffset[0], fileNoffset[1]);

							}
							System.out.println(fileMap);
							break;
						}

					}

				} else {
					System.out.println("Please connect to a server first.");
				}

			} else if (choice == 3) {
				if (fileMap.isEmpty()) {
					System.out.println("You have not requested for the "
							+ "file list from server yet.");
					choice = 2;

				} else {
					System.out.println(fileMap);
					System.out
							.print("Enter file names you want to download (file1.txt,file2.txt):");
					// Check if files are in the temp directory
					// scan.nextLine();
					// Scan in the list of files
					String input = scan.next();
					// Print out what they selected
					System.out.println("You selected:" + input);
					// Split the list of files by commas
					String[] tokens = input.split(",");
					// ArrayList<String> list = new ArrayList<String>(
					// Arrays.asList(files));

					for (String s : tokens) {
						if (fileMap.containsKey(s)) {

							String msg = "3-";

							// File f = new File("ClientHome");
							// System.out.println(f.getAbsolutePath());

							long totalOffset = 0;

							// if (f.exists()) {
							// totalOffset = f.length() / 1024;
							// }

							msg += s + ":" + String.valueOf(totalOffset) + ",";

							// remove trailing comma
							msg = msg.substring(0, msg.length() - 1);
							out.println(msg);
							out.flush();
							// Print out the message of what I got/continue from
							// that offset
							System.out.println("Sending to server:" + msg);
							String inputLine = "";
							// while ((inputLine = in.readLine()) != null) {
							// System.out.println("Got from server:"+inputLine);
							// String[] srvRsp = inputLine.split("-");
							// if (inputLine.contains("0")){
							// System.out.println("GOT 0"+srvRsp[1]);
							// is = s.getInputStream();
							// for (String key : tokens) {
							try {

								fos = new FileOutputStream("ClientHome/TEST"
										+ s, true);
								bos = new BufferedOutputStream(fos);

							} catch (FileNotFoundException ex) {
								System.out.println("File not found. ");
							}

							byte[] bytes = new byte[1024];

							int count;
							System.out.println("Client's reading from server");
							while ((count = bis.read(bytes)) > 0) {
								System.out.println(count);
								bos.write(bytes, 0, count);
							}
							System.out.println("Client's done");
							fos.flush();
							bos.flush();
							fos.close();
							bos.close();
							System.out.println("Downloaded " + s);
							// }
							// }else{
							// System.out.println("Could not find "+
							// srvRsp[1]+"skipping...");
							// }
							// }

						} else {
							System.out
									.println("Your response do not match our available files for download. Please try again.");
						}
					}
				}

				// Upload file to server
			} else if (choice == 4) {
				File dir = new File("ClientHome");
				String[] fileList = dir.list();
				System.out.println("Available files:");
				for (String f : fileList) {
					System.out.println(f);
				}
				System.out.print("Please enter files you want to upload:");
				String selection = scan.nextLine();
				// Remove extra spaces
				selection = selection.replaceAll(" ", "");
				String[] uploadList = selection.split(",");
				// Sending File Summary, then get back the server's
				// filename:offset
				// Send the file from that offset, go back to loop.
				for (String up : uploadList) {
					File ff = new File("ClientHome/" + up);

					if (ff.exists()) {
						// Divide up the size
						int offsetTotal = (int) (ff.length() / 1024);
						// I'm sending you my summary of the first file I'll
						// upload to you
						String msg = MsgCode.FILE_SUMMARY + ":" + up + ":"
								+ String.valueOf(offsetTotal);
						out.write(msg);
						out.flush();
						System.out.println("Sending " + ff.getName() + "...");
						String inputLine = "";
						while ((inputLine = in.readLine()) != null) {
							// I expect your response to be #3, what you have
							int serverOffset = 0;
							if (inputLine.contains("3")) {
								String[] response = inputLine.split("-");
								String[] files = response[1].split(",");
								for (String f : files) {
									String[] sect = f.split(":");
									byte[] bytes = new byte[(int) 1024];
									serverOffset = Integer.valueOf(sect[1]);
									FileInputStream fis = new FileInputStream(
											sect[0]);
									BufferedInputStream bis = new BufferedInputStream(
											fis);
									int count = 0;
									int offset = 0;
									while ((count = bis.read(bytes)) > 0) {
										if (offset > serverOffset) {
											bout.write(bytes, 0, count);
										}
										offset++;
									}
									bout.flush();
									fis.close();
									bis.close();

								}

							}

						}
					} else {
						System.out.println("File" + up.toString()
								+ " does not exist. Skipping...");

					}
				}
			}
		}
		if (s != null) {
			try {
				s.close();
				out.close();
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("Have a nice day!");
	}

	public static void main(String[] args) throws IOException {
		Client c = new Client();
		c.run();
	}

}
